package top.blentle.ai.data.listener;

import okio.BufferedSource;
import okio.Okio;
import org.apache.activemq.command.ActiveMQBytesMessage;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import top.blentle.ai.data.endpoint.EventType;
import top.blentle.ai.data.endpoint.JsonDataMsg;
import top.blentle.ai.data.endpoint.WebSocketServer;

import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.Message;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.Charset;

/**
 * @author renhuan
 * @desc
 */
@Component
public class TopicListener {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private WebSocketServer server;

    @JmsListener(destination = "jack_mqtt_test", containerFactory = "jmsListenerContainerTopic")
    public void receive(Message message) throws JMSException, IOException {
        if (message instanceof ActiveMQBytesMessage) {
            ActiveMQBytesMessage msg = (ActiveMQBytesMessage) message;
            int len = (int) msg.getBodyLength();
            byte[] buffer = new byte[len];
            msg.readBytes(buffer);
            logger.info("received: 【{}】 bytes from client ,content:【{}】", len, bytesToHexString(buffer));
            ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
            BufferedSource bs = Okio.buffer(Okio.source(bis));
            bis.close();
            byte head = bs.readByte();
            //head右移5位与上0x07得到前三位
            /**
             * 版本号:从0开始
             */
            int version = getFirstPartOfByte(head);
            /**
             * 0:数据:设备终端数据
             * 1:数据：事件通知
             * 2:数据:设备配置
             * 3:命令:获取服务端下发数据
             * 4:命令:获取校准时间
             * 5:同步同型号设备配置
             */
            int type = getSecondPartOfByte(head);
            /**
             * 总是0，备用字段，暂时没用
             */
            int last = getLastPartOfByte(head);
            String deviceId = bs.readByteString(12).hex();
            logger.info("version:【{}】,type:【{}】,last:【{}】 deviceId :【{}】", version, type, last, deviceId);
            //剩余电量 0-100 单位
            byte remain = bs.readByte();
            //这个字节有供电方式,工作场景，备用
            byte elec = bs.readByte();
            //供电方式 0:电源 1:电池
            int powerType = (elec >> 7) & 0x01;
            //工作场景 0:室外 1：室内
            int scene = (elec >> 6) & 0x02;
            //备用
            int prepareOfElec = (elec >> 2) & 0x3f;
            //通信方式 0：wifi 1:gprs
            byte communicateType = bs.readByte();
            //设备厂家
            int deviceFactory = bs.readInt();
            //设备型号
            int deviceMode = bs.readInt();
            //解析协议体
            resolveBody(type, bs);
            bs.close();
        } else if (message instanceof ActiveMQTextMessage) {
            ActiveMQTextMessage msg = (ActiveMQTextMessage) message;
            logger.info("received: 【{}】 bytes from client... ", msg.getText());
            JsonDataMsg data = new JsonDataMsg(EventType.data, "这是通过Controller调用Topic获取的数据" + msg.getText());
            server.send(data);
            message.acknowledge();
        }

    }

    /**
     * 解析协议体
     *
     * @param type
     * @param bs
     */
    private void resolveBody(int type, BufferedSource bs) throws IOException {
        switch (type) {
            //数据监测上报
            case 0:
                handleReport(bs);
                break;
            //事件通知
            case 1:
                handleEvent(bs);
                break;
            //设备配置
            case 2:
                handleDeviceConfig(bs);
                break;
            //3：命令:获取服务端下发数据
            case 3:
                break;
            //4.命令:获取校准时间
            case 4:
                break;
            //5.命令:同步同型号设备
            case 5:
                break;
            default:
                logger.error("错误的消息类型:...{" + type + "}....");
                break;

        }
    }

    /**
     * 处理设备配置
     *
     * @param bs
     */
    private void handleDeviceConfig(BufferedSource bs) throws IOException {
        short totalLen = bs.readShort();
        int leftLen = totalLen - 2;
        byte[] left = bs.readByteArray(leftLen);
        String configs = new String(left, Charset.forName("GBK"));
        String[] configArr = configs.split("\t");
        if (configArr != null) {
            for (String config : configArr) {
                String[] kvArr = config.split("=");
                if (kvArr != null) {
                    String key = kvArr[0];
                    String val = kvArr[1];
                    logger.info("配置键值对儿:{}:{}", key, val);
                }
            }
        }
    }

    /**
     * 处理事件通知
     *
     * @param bs
     */
    private void handleEvent(BufferedSource bs) throws IOException {
        byte year = bs.readByte();
        byte month = bs.readByte();
        byte day = bs.readByte();
        byte hour = bs.readByte();
        byte minute = bs.readByte();
        byte second = bs.readByte();
        /**
         * 事件类别
         * 0:系统
         * 1:GPRS
         * 2:存储
         * 3:电池
         * 4：命令响应
         * 5:传感器1
         * 6：传感器2
         *
         */
        byte eventCategory = bs.readByte();
        /**
         * 具体的事件
         * 系统：
         * 0：启动，正常上电
         * 1：启动平台命令
         * 2：启动设备故障
         * 3：启动恢复出场设置
         *
         * 电池：
         * 0：电池故障
         * 1:低电压警告
         *
         * 传感器2：
         * 0：读取数据失败
         * 1：传感器故障
         */
        byte event = bs.readByte();

        short param = bs.readShort();

    }

    /**
     * 处理数据上报
     *
     * @param bs
     * @throws IOException
     */
    private void handleReport(BufferedSource bs) throws IOException {
        //获取数据头:
        short totalLen = bs.readShort();
        //参数的个数:
        byte paramCount = bs.readByte();
        //参数编码列表:
        byte[] paramEncList = bs.readByteArray(paramCount);
        //数据条数
        byte dataCount = bs.readByte();
        //读数据体:
        for (int i = 0; i < dataCount; i++) {
            //读前面的数据:
            /**
             * 标志位:
             * 0:正常数据
             * 1:校准
             * 2：维护
             * 3：故障
             * 4：平台端修正(仅用于平台端存储)
             */
            byte flag = bs.readByte();
            byte year = bs.readByte();
            byte month = bs.readByte();
            byte day = bs.readByte();
            byte hour = bs.readByte();
            byte minute = bs.readByte();
            byte second = bs.readByte();
            //读参数
//            for (int j = 0; j < paramCount; j++) {
//                //参数代码:
//                byte code = paramEncList[j];
//                switch (code) {
//                    //SO2
//                    case (byte) 0:
//                        short so2 = bs.readShort();
//                        break;
//                    //NO2
//                    case (byte) 1:
//                        short no2 = bs.readShort();
//                        break;
//                    //CO
//                    case (byte) 2:
//                        byte colorR = bs.readByte();
//                        logger.info("颜色R值：【{}】",colorR);
//                        break;
//                    //O3
//                    case (byte) 3:
//                        byte colorG = bs.readByte();
//                        logger.info("颜色G值：【{}】",colorG);
//                        break;
//                    //pm10
//                    case (byte) 4:
//                        byte colorB = bs.readByte();
//                        logger.info("颜色B值：【{}】",colorB);
//                        break;
//
//                    default:
//                        logger.error("错误的参数代码:...{" + code + "}....");
//                        break;
//                }
//            }
        }
    }

    /**
     * 获取一个字节的前三位
     *
     * @param b
     * @return
     */
    private int getFirstPartOfByte(byte b) {
        return (b >> 5) & 0x07;
    }

    /**
     * 获取一个字节的中间三位
     *
     * @param b
     * @return
     */
    private int getSecondPartOfByte(byte b) {
        return (b >> 2) & 0x07;
    }

    /**
     * 获取一个字节的后2位
     *
     * @param b
     * @return
     */
    private int getLastPartOfByte(byte b) {
        return b & 0x03;
    }

    /**
     * 二进制转16进制
     *
     * @param bArray
     * @return
     */
    private static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 16进制转2进制
     * @param hex
     * @return
     */
    private static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static byte toByte(char c) {
        byte b = (byte) "0123456789abcdef".indexOf(c);
        return b;
    }

}
